package cn.shadow.server;


import cn.shadow.message.WorkerFactory;
import cn.shadow.server.hanlder.SingleDecodeHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.DefaultThreadFactory;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

import java.io.Closeable;
import java.net.InetSocketAddress;
import java.util.concurrent.ThreadFactory;

@Slf4j
public class NettyServer implements Closeable {
    private EventLoopGroup bossGroup;
    private EventLoopGroup workGroup;
    private ServerBootstrap bootstrap;
    private ChannelGroup group;
    private int port;

    public NettyServer(int port, WorkerFactory workerFactory) {
        this.port = port;
        ThreadFactory bf = new DefaultThreadFactory("boss线程", false, 5);
        this.group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        this.bossGroup = new NioEventLoopGroup(1, bf);
        ThreadFactory wf = new DefaultThreadFactory("worker线程", false, 5);
        this.workGroup = new NioEventLoopGroup(16, wf);
        this.bootstrap = new ServerBootstrap();
        this.bootstrap.group(bossGroup, workGroup);
        this.bootstrap.channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel socketChannel) {
                ChannelPipeline pipeline = socketChannel.pipeline();
                pipeline.addLast(new IdleStateHandler(10, 10, 0));
//                pipeline.addLast("idleStateTrigger", new ServerIdleStateTrigger());
                pipeline.addLast("frameDecoder", new SingleDecodeHandler(workerFactory, group));
                pipeline.addLast("frameEncoder", new LengthFieldPrepender(4));
            }
        });
    }

    public void start() {
        try {
            ChannelFuture future = bootstrap.bind(new InetSocketAddress(port)).sync();
            log.info("Server start listen at " + port);
            future.channel().closeFuture().addListener(f -> {
                if (f.isSuccess()) {
                    bossGroup.shutdownGracefully();
                    workGroup.shutdownGracefully();
                }
            });
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void close() {
    }
}
